/*
 * @description 开放签
 *
 * Copyright (C) [2025] [版权所有者（北京资源律动科技有限公司）]. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * 注意：本代码基于 AGPLv3 协议发布。若通过网络提供服务（如 Web 应用），
 * 必须公开修改后的完整源码（包括衍生作品），详见协议全文。
 */

import type { AppRouteRecordRaw, Menu, SensitiveItem } from '/@/router/types';

import { defineStore } from 'pinia';
import { store } from '/@/store';
import { useUserStore } from './user';
import { useAppStoreWithOut } from './app';
import { toRaw } from 'vue';
import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper';
import { transformRouteToMenu } from '/@/router/helper/menuHelper';


import projectSetting from '/@/settings/projectSetting';

import { PermissionModeEnum } from '/@/enums/appEnum';

import { asyncRoutes, ApplicationInsideRoute } from '/@/router/routes';

import { getHashQueryString } from '/@/utils';

import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE, PAGE_INSIDE_LINK } from '/@/router/routes/basic';


import { filter } from '/@/utils/helper/treeHelper';

import { getMenuList } from '/@/api/sys/menu';
import { getPermCode, getSensitiveCode } from '/@/api/sys/user';

import { useMessage } from '/@/hooks/web/useMessage';
import { PageEnum } from '/@/enums/pageEnum';

interface PermissionState {
    // Permission code list
    permCodeList: string[] | number[];
    //sensitive operation list 
    sensitiveList: SensitiveItem[],
    // Whether the route has been dynamically added
    isDynamicAddedRoute: boolean;
    // To trigger a menu update
    lastBuildMenuTime: number;
    // Backstage menu list
    backMenuList: Menu[];
    frontMenuList: Menu[];
}

export const usePermissionStore = defineStore({
    id: 'app-permission',
    state: (): PermissionState => ({
        permCodeList: [],
        //sensitive operation list 
        sensitiveList: [],
        // Whether the route has been dynamically added
        isDynamicAddedRoute: false,
        // To trigger a menu update
        lastBuildMenuTime: 0,
        // Backstage menu list
        backMenuList: [],
        // menu List
        frontMenuList: [],
    }),
    getters: {
        getPermCodeList(): string[] | number[] {
            return this.permCodeList;
        },
        getSensitiveList(): SensitiveItem[] {
            return this.sensitiveList
        },
        getBackMenuList(): Menu[] {
            return this.backMenuList;
        },
        getFrontMenuList(): Menu[] {
            return this.frontMenuList;
        },
        getLastBuildMenuTime(): number {
            return this.lastBuildMenuTime;
        },
        getIsDynamicAddedRoute(): boolean {
            return this.isDynamicAddedRoute;
        },
    },
    actions: {
        setPermCodeList(codeList: string[]) {
            this.permCodeList = codeList;
        },

        setSensitiveList(list: SensitiveItem[]) {
            this.sensitiveList = list;
        },

        setBackMenuList(list: Menu[]) {
            this.backMenuList = list;
            list?.length > 0 && this.setLastBuildMenuTime();
        },

        setFrontMenuList(list: Menu[]) {
            this.frontMenuList = list;
        },

        setLastBuildMenuTime() {
            this.lastBuildMenuTime = new Date().getTime();
        },

        setDynamicAddedRoute(added: boolean) {
            this.isDynamicAddedRoute = added;
        },
        resetState(): void {
            this.isDynamicAddedRoute = false;
            this.permCodeList = [];
            this.backMenuList = [];
            this.lastBuildMenuTime = 0;
        },
        async changePermissionCode() {
            const codeList = await getPermCode();
            this.setPermCodeList(codeList);
        },
        async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
            const userStore = useUserStore();
            const appStore = useAppStoreWithOut();

            let routes: AppRouteRecordRaw[] = [];
            const roleList = toRaw(userStore.getRoleList) || [];
            const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;

            const routeFilter = (route: AppRouteRecordRaw) => {
                const { meta } = route;
                const { roles } = meta || {};
                if (!roles) return true;
                return roleList.some((role) => roles.includes(role));
            };

            const routeRemoveIgnoreFilter = (route: AppRouteRecordRaw) => {
                const { meta } = route;
                const { ignoreRoute } = meta || {};
                return !ignoreRoute;
            };

            /**
             * @description 根据设置的首页path，修正routes中的affix标记（固定首页）
             * */
            const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
                if (!routes || routes.length === 0) return;
                let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
                function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
                    if (parentPath) parentPath = parentPath + '/';
                    routes.forEach((route: AppRouteRecordRaw) => {
                        const { path, children, redirect } = route;
                        const currentPath = path.startsWith('/') ? path : parentPath + path;
                        if (currentPath === homePath) {
                            if (redirect) {
                                homePath = route.redirect! as string;
                            } else {
                                route.meta = Object.assign({}, route.meta, { affix: true });
                                throw new Error('end');
                            }
                        }
                        children && children.length > 0 && patcher(children, currentPath);
                    });
                }
                try {
                    patcher(routes);
                } catch (e) {
                    // 已处理完毕跳出循环
                }
                return;
            };

            switch (permissionMode) {
                case PermissionModeEnum.ROLE:
                    routes = filter(asyncRoutes, routeFilter);
                    routes = routes.filter(routeFilter);
                    // Convert multi-level routing to level 2 routing
                    routes = flatMultiLevelRoutes(routes);
                    break;

                case PermissionModeEnum.ROUTE_MAPPING:
                    routes = filter(asyncRoutes, routeFilter);
                    routes = routes.filter(routeFilter);
                    const menuList = transformRouteToMenu(routes, true);
                    routes = filter(routes, routeRemoveIgnoreFilter);
                    routes = routes.filter(routeRemoveIgnoreFilter);
                    menuList.sort((a, b) => {
                        return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0);
                    });

                    this.setFrontMenuList(menuList as Menu[]);
                    // Convert multi-level routing to level 2 routing
                    routes = flatMultiLevelRoutes(routes);
                    break;

                //  If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
                case PermissionModeEnum.BACK:
                    const { createMessage } = useMessage();

                    createMessage.loading({
                        content: '加载中...',
                        duration: 1,
                    });
                    
                    let routeList: AppRouteRecordRaw[] = [];
                    try {
                        // this.changePermissionCode();
                        let permissionResult = await getMenuList();
                        if(!permissionResult.menuTree || permissionResult.menuTree.length == 0){
                          console.log("没有权限跳出");
                          break;
                        }
                        userStore.setPermissionInfo({
                            authList: permissionResult.authList,
                            menuTree: permissionResult.menuTree
                        })
                        let sensitiveResult = await getSensitiveCode();
                        this.setPermCodeList(permissionResult.authList);
                        this.setSensitiveList(sensitiveResult);
                        routeList = permissionResult.menuTree as AppRouteRecordRaw[];

                    } catch (error) {
                        console.error(error);
                    }

                    // Dynamically introduce components
                    routeList = transformObjToRoute(routeList);

                    //  Background routing to menu structure
                    // // 添加默认基础路由
                    // routeList = [PAGE_INSIDE_LINK,...routeList];
                    const backMenuList = transformRouteToMenu(routeList);

                    //判断是否为应用管理内部页面
                    if (getHashQueryString('type') == 'application') {
                        const menuList = transformRouteToMenu([ApplicationInsideRoute]);

                        this.setBackMenuList(menuList as Menu[]);
                        routes = [PAGE_NOT_FOUND_ROUTE, PAGE_INSIDE_LINK, ApplicationInsideRoute];
                    } else {
                        this.setBackMenuList(backMenuList as Menu[]);
                        // remove meta.ignoreRoute item
                        routeList = filter(routeList, routeRemoveIgnoreFilter);
                        routeList = routeList.filter(routeRemoveIgnoreFilter);

                        routeList = flatMultiLevelRoutes(routeList);
                        // routeList.sort((a,b)=>{return b.sortNo - a.sortNo});
                        routeList.reverse()
                        routes = [...routeList, PAGE_NOT_FOUND_ROUTE, PAGE_INSIDE_LINK,];
                    }
                    break;
            }

            routes.push(ERROR_LOG_ROUTE);
            patchHomeAffix(routes);

            routes.sort((a, b) => {
                return a.sortNo - b.sortNo;
            })

            return routes;
        },
    },
});

// Need to be used outside the setup
export function usePermissionStoreWithOut() {
    return usePermissionStore(store);
}
